#include <vector>
#include <pthread.h>
#include <semaphore.h>

using namespace std;

template <class T>
class RingQueue
{
public:
    RingQueue(int cap)
    :_cap(cap)
    {
        _q.resize(_cap);
        _product_step=0;
        _consum_step=0;
        
        pthread_mutex_init(&_product_mutex, nullptr);
        pthread_mutex_init(&_consum_mutex, nullptr);

        sem_init(&_room_sem, 0, _cap);//第二个参数，0是线程间共享，非0是进程间共享
        sem_init(&_data_sem,0, 0);
    }

    void Enqueue(const T& in)
    { 
        sem_wait(&_room_sem);//信号量自个有锁保护计数器

        pthread_mutex_lock(&_product_mutex);
        _q[_product_step++]= in;
        _product_step%= _cap;
        pthread_mutex_unlock(&_product_mutex);


        sem_post(&_data_sem);
    }

    void Pop(T* out)
    {
        sem_wait(&_data_sem);//为什么需要锁来保护环形队列，因为初始情况data_sem为cap，
        //所以会有很多进程同时能在data_sem的wait下不阻塞，同时访问环形队列，因此必须加保护

        pthread_mutex_lock(&_consum_mutex);
        *out= _q[_consum_step++];
        _consum_step%= _cap;
        pthread_mutex_unlock(&_consum_mutex);


        sem_post(&_room_sem);
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&_product_mutex);
        pthread_mutex_destroy(&_consum_mutex);
    }

private:
    vector<T> _q;
    int _cap;//环形队列的大小
    int _product_step;
    int _consum_step;

    pthread_mutex_t _product_mutex;//环形队列的队列本身还有下标是多个线程的共享资源，所以要用锁保护
    pthread_mutex_t _consum_mutex;

    sem_t _room_sem;
    sem_t _data_sem;

    //3个关系，两个互斥的关系，一个同步的关系
};